#pragma once

#include <sys/types.h>
#include <sys/socket.h>
#include "Connection.hpp"
#include "InetAddr.hpp"

class HandlerConnection
{
public:
    HandlerConnection(func_t func) : _func(func)
    {
        std::cout << &_func << std::endl;
    }
    HandlerConnection() = delete;
    // HandlerConnection(const HandlerConnection &) = delete;
    // HandlerConnection &operator=(const HandlerConnection &) = delete;

    void HandlerRecv(Connection *conn)
    {
        errno = 0;
        if (!_func)
        {
            std::cout << "bad func & return" << std::endl;
            return;
        }
        LOG(DEBUG, "HanlderRecv fd : %d\n", conn->Sockfd());
        while (true)
        {
            char inbuffer[1024] = {0};
            int n = ::recv(conn->Sockfd(), inbuffer, sizeof(inbuffer), 0);
            if (n > 0)
            {
                inbuffer[n] = 0;
                conn->AppendInbuffer(inbuffer);
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    conn->excepter()(conn);
                    return;
                }
            }
        }
        _func(conn);
    }
    void HandlerSend(Connection *conn)
    {
        errno = 0;
        while (true)
        {
            ssize_t n = ::send(conn->Sockfd(), conn->Outbuffer().c_str(), conn->Outbuffer().size(), 0);
            if (n > 0)
            {
                conn->OutbufferRemove(n);
                if (conn->Outbuffer().empty())
                    break;
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    conn->excepter()(conn);
                    return;
                }
            }
        }
        if (!conn->Outbuffer().empty())
        {
            conn->Self()->EnableReadWrite(conn->Sockfd(), true, true);
        }
        else
        {
            conn->Self()->EnableReadWrite(conn->Sockfd(), true, false);
        }
    }
    void HandlerExcept(Connection *conn)
    {
        errno = 0;
        LOG(DEBUG, "client quit : %d\n", conn->Sockfd());
        conn->Self()->DelConnection(conn->Sockfd());
    }
    ~HandlerConnection() {}

private:
    func_t _func;
};
